package com.hulk.dryad.manage.framework.datasource;

import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.ds.ItemDataSource;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hulk.dryad.common.constant.enums.DelFlag;
import com.hulk.dryad.persistence.entity.GenDatasourceConfModel;
import com.hulk.dryad.persistence.entity.enums.DsConfTypeEnum;
import com.hulk.dryad.persistence.entity.enums.DsJdbcUrlEnum;
import com.hulk.dryad.manage.provider.service.GenDatasourceConfService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/** @author hulk */
@Slf4j
@Component
@RequiredArgsConstructor
public class DruidDataSourceRunner implements CommandLineRunner {

  @Value("${spring.datasource.dynamic.primary:DB_0}")
  private String primary;

  private final GenDatasourceConfService datasourceConfService;
  private final DynamicRoutingDataSource dynamicRoutingDataSource;

  @Override
  public void run(String... args) {
    try {
      DynamicDataSourceHolder.set(primary);
      List<GenDatasourceConfModel> dsList = datasourceConfService.list();
      Set<String> dsNames = new HashSet<>();
      if (dsList == null || dsList.isEmpty()) {
        log.info("项目启动时动态添加数据源为0个");
        return;
      }
      Map<String, DataSource> mds = dynamicRoutingDataSource.getCurrentDataSources();
      Set<String> poolNames =
          mds.entrySet().stream().map((entry) -> entry.getKey()).collect(Collectors.toSet());
      for (GenDatasourceConfModel model : dsList) {
        Integer confType = model.getConfType();
        String dsType = model.getDsType();
        String name = model.getName();
        dsNames.add(name);
        if (poolNames.contains(name)) {
          continue;
        }
        String url;
        // JDBC 配置形式
        DsJdbcUrlEnum urlEnum = DsJdbcUrlEnum.get(dsType);
        if (DsConfTypeEnum.JDBC.getType().equals(confType)) {
          url = model.getUrl();
        } else if (DsJdbcUrlEnum.MSSQL.getDbName().equals(dsType)) {
          String host = model.getHost();
          Integer port = model.getPort();
          String dsName = model.getDsName();
          String instance = model.getInstance();
          url = String.format(urlEnum.getUrl(), host, instance, port, dsName);
        } else {
          String host = model.getHost();
          Integer port = model.getPort();
          String dsName = model.getDsName();
          url = String.format(urlEnum.getUrl(), host, port, dsName);
        }

        model.setUrl(url);
        // 添加动态数据源
        datasourceConfService.addDynamicDataSource(model);
        log.info("项目启动时动态添加数据源信息:[{}]", model);
      }
      Set<String> result = new HashSet<>();
      result.addAll(poolNames);
      result.removeAll(dsNames);
      result.stream()
          .forEach(
              v -> {
                ItemDataSource ids = (ItemDataSource) mds.get(v);
                DruidDataSource dds = (DruidDataSource) ids.getRealDataSource();
                GenDatasourceConfModel model = new GenDatasourceConfModel();
                model.setName(v);
                model.setUsername(dds.getUsername());
                model.setPassword(dds.getPassword());
                model.setConfType(DsConfTypeEnum.JDBC.getType());
                model.setDelFlag(DelFlag.N.getValue());
                String dbType = dds.getDbType();
                model.setDsType(dbType);
                if (DsJdbcUrlEnum.MSSQL.getDbName().equals(dbType)) {
                  String instance = model.getInstance();
                  model.setInstance(instance);
                }
                model.setUrl(dds.getUrl());
                //				model.setDsName("");
                //				model.setHost("");
                //				model.setPort(0);
                model.setCreatedTime(LocalDateTime.now());
				log.info("项目启动时内存中数据源同步到数据库中:[{}]", model);
				  LambdaUpdateWrapper<GenDatasourceConfModel> uw = Wrappers.<GenDatasourceConfModel>lambdaUpdate()
						  .eq(GenDatasourceConfModel::getName, v);
                datasourceConfService.saveOrUpdate(model,uw);
              });
      log.info("项目启动时动态添加数据源为[{}]个", dsList.size());
    } catch (Exception e) {
      e.printStackTrace();
      log.error(e.getMessage(), e);
    } finally {
      DynamicDataSourceContextHolder.clear();
    }
  }
}
